﻿using System;
using System.IO;
using System.Net;
using System.Runtime.InteropServices;
using HtmlAgilityPack;
using Microsoft.Win32;

namespace AQMProject
{
    // Ersetzen Sie die GUID unten mit einer eigenen GUID.
    // Sie generieren eine eigene GUID mit Extras-> GUID erstellen und wählen Sie
    // Punkt 4. Registrierungsformat.

    // GUID = Globally Unique Identifier
    // Wird intern zur Identifizierung von Klassen und Interfaces von COM Objekten benötigt.
    // Die Aktivierung der Klasse oder des Objektes kann ohne Kenntnis des Ortes oder des Namens
    // der DLL (Dynamic Linked Library) erfolgen. Sie können die GUID dann generieren, kopieren
    // und in Ihren Code einfügen.

    [Guid("7749735C-FED2-4546-BD14-0D21B042B9CE")]

    #region Interface
    [ClassInterface(ClassInterfaceType.AutoDual)]
    [ComVisible(true)]
    #endregion

    public class Mydoubles
    {
        #region Konstruktor
        public Mydoubles()
        {
        }
        #endregion

        #region Beispiel Carter/Lipper S.99

        // Beispiel aus Carter/Lippert, Visual Studio Tools for Office 2007, S. 99 ff.

        public double MultiplyNTimes(double number1,
          double number2, double timesToMultiply)
        {
            double result = number1;
            for (double i = 0; i < timesToMultiply; i++)
            {
                result = result * number2;
            }
            return result;
        }
        #endregion

        // User defined double (UDF) für Excel zur Kursabfrage bei Yahoo Finance.
        // Methode liefert einen Single-Wert zurück, daher nur für Parameter
        // geeignet bei denen Yahoo Finance ein Single-Ergebnis liefert, sonst
        // ungültiger Wert.


        public Single Online_Kurs(string ticker, string parameter)
        {
            string url;

            // Der Ticker sagt welches Wertpapier
            // Der Parameter sagt welche Information des Wertpapiers, z.B. l1 = letzter Kurs
            // Die Methode ist nur für Single-Werte geeignet!!

            url = "http://download.finance.yahoo.com/d/quotes.csv?s=" + ticker + "&f=" + parameter + "&e=.csv";

            // siehe auch MSDN Library unter WebRequest-Klasse
            // http://msdn.microsoft.com/de-de/library/system.net.webrequest(VS.80).aspx

            // Create a request for the URL. 
            WebRequest request = WebRequest.Create(url);

            // If required by the server, set the credentials.
            request.Credentials = CredentialCache.DefaultCredentials;

            // Get the response.
            WebResponse response = request.GetResponse();

            #region Comment
            // Display the status.
            // Console.WriteLine(((HttpWebResponse)response).StatusDescription); 
            #endregion

            // Get the stream containing content returned by the server.
            Stream dataStream = response.GetResponseStream();

            // Open the stream using a StreamReader for easy access.
            StreamReader reader = new StreamReader(dataStream);

            // Read the content.
            string responseFromServer = reader.ReadToEnd();

            // Clean up the streams and the response.
            reader.Close();
            response.Close();

            // Tausche Punkt gegen Komma (US-Schreibweise) und wandle in Fliesskomma um

            return (Convert.ToSingle(responseFromServer.Replace(".", ",")));
        }

        public String Online_Kurs_Name(string ticker, string parameter)
        {
            string url;

            // ticker sagt welches Wertpapier
            // parameter sagt welche Information des Wertpapiers, z.B. n0 = Name des Wertpapiers
            // nur für Strings geeignet!!

            url = "http://download.finance.yahoo.com/d/quotes.csv?s=" + ticker + "&f=" + parameter + "&e=.cvs";

            // siehe auch MSDN Library unter WebRequest-Klasse
            // http://msdn.microsoft.com/de-de/library/system.net.webrequest(VS.80).aspx

            // Create a request for the URL. 
            WebRequest request = WebRequest.Create(url);

            // If required by the server, set the credentials.
            request.Credentials = CredentialCache.DefaultCredentials;

            // Get the response.
            WebResponse response = request.GetResponse();

            #region Comment
            // Display the status.
            // Console.WriteLine(((HttpWebResponse)response).StatusDescription); 
            #endregion

            // Get the stream containing content returned by the server.
            Stream dataStream = response.GetResponseStream();

            // Open the stream using a StreamReader for easy access.
            StreamReader reader = new StreamReader(dataStream);

            // Read the content.
            string responseFromServer = reader.ReadToEnd();

            // Clean up the streams and the response.
            reader.Close();
            response.Close();

            // Entferne die Anführungszeichen

            return (responseFromServer.Replace('"', ' ').Trim());
        }

        public String Online_Kurs_Option(string ticker, string contract, string basis, string ex, string parameter)
        {
            // Beispiel für die Abfrage von Optionen
            // Search for bid:    <span id="yfs_b00_ibm110917c00110000">
            // Search for ask:    <span id="yfs_a00_ibm110917c00110000">
            // Search for last:   <span id="yfs_l10_ibm110917c00110000">

            string head = "http://finance.yahoo.com/q?s=";
            string typ;


            switch (parameter)
            {
                case "l":
                    parameter = parameter + "10";
                    break;
                case "a":
                    parameter = parameter + "00";
                    break;
                case "b":
                    parameter = parameter + "00";
                    break;
                default:
                    parameter = "l10";
                    break;
            }

            typ = "//span[contains(@id,'yfs_" + parameter + "')]";

            string x = head + ticker + ex + contract + "00" + basis + "000";

            // http://finance.yahoo.com/q?s=ibm110917C00110000

            HtmlWeb YahooWeb = new HtmlWeb();
            HtmlAgilityPack.HtmlDocument doc = YahooWeb.Load(x);
            HtmlNode MyLastNode = doc.DocumentNode.SelectSingleNode(typ);

            if (MyLastNode != null)
            {
                return (MyLastNode.InnerText.Replace(".", ","));
            }
            else
            {
                return ("n.a.");
            }
        }

        public double Call_Option_BSM_Model(double Stock, double Exercise, double Time, double Interest, double sigma)
        {
            return (Stock * NormSDist(dOne(Stock, Exercise, Time, Interest, sigma)) - Exercise * Math.Exp(-Time * Interest) * NormSDist(dOne(Stock, Exercise, Time, Interest, sigma) - sigma * Math.Sqrt(Time)));
        }

        public double Put_Option_BSM_Model(double Stock, double Exercise, double Time, double Interest, double sigma)
        {
            return (Exercise * Math.Exp(-Time * Interest) * NormSDist(-dOne(Stock, Exercise, Time, Interest, sigma) + sigma * Math.Sqrt(Time)) - Stock * NormSDist(-dOne(Stock, Exercise, Time, Interest, sigma)));
        }

        public double dOne(double Stock, double Exercise, double Time, double Interest, double sigma)
        {
            return (Math.Log(Stock / Exercise) + Interest * Time) / (sigma * Math.Sqrt(Time)) + 0.5 * sigma * Math.Sqrt(Time);
        }

        public double NormSDist(double x)
        {
            double L = 0.0;
            double K = 0.0;
            double dCND = 0.0;

            const double a1 = 0.31938153;
            const double a2 = -0.356563782;
            const double a3 = 1.781477937;
            const double a4 = -1.821255978;
            const double a5 = 1.330274429;

            L = Math.Abs(x);

            K = 1.0 / (1.0 + 0.2316419 * L);

            dCND = 1.0 - 1.0 /

            Math.Sqrt(2 * Convert.ToDouble(Math.PI.ToString())) * Math.Exp(-L * L / 2.0) * (a1 * K + a2 * K * K + a3 * Math.Pow(K, 3.0) + a4 * Math.Pow(K, 4.0) + a5 * Math.Pow(K, 5.0));

            if (x < 0)
            {
                return 1.0 - dCND;
            }
            else
            {
                return dCND;
            }
        }

        public double nstrich(double x)
        {
            return (Math.Exp(-0.5 * x * x) / Math.Sqrt(2 * Math.PI));
        }

        public double PutDelta(double Stock, double Exercise, double Time, double Interest, double sigma)
        {
            return (NormSDist(dOne(Stock, Exercise, Time, Interest, sigma)) - 1);
        }

        public double CallDelta(double Stock, double Exercise, double Time, double Interest, double sigma)
        {
            return (NormSDist(dOne(Stock, Exercise, Time, Interest, sigma)));
        }

        public double Gamma(double Stock, double Exercise, double Time, double Interest, double sigma)
        {
            return (nstrich(dOne(Stock, Exercise, Time, Interest, sigma)) / (Stock * sigma * Math.Sqrt(Time)));
        }

        public double PutOmega(double Stock, double Exercise, double Time, double Interest, double sigma)
        {
            return (-1 * ((NormSDist(dOne(Stock, Exercise, Time, Interest, sigma) * (-1))) * (Stock / (Put_Option_BSM_Model(Stock, Exercise, Time, Interest, sigma)))));
        }

        public double CallOmega(double Stock, double Exercise, double Time, double Interest, double sigma)
        {
            return (NormSDist(dOne(Stock, Exercise, Time, Interest, sigma)) * (Stock / (Call_Option_BSM_Model(Stock, Exercise, Time, Interest, sigma))));
        }

        public double Vega(double Stock, double Exercise, double Time, double Interest, double sigma)
        {
            return (Stock * nstrich(dOne(Stock, Exercise, Time, Interest, sigma)) * Math.Sqrt(Time));
        }

        public double PutTheta(double Stock, double Exercise, double Time, double Interest, double sigma)
        {
            return (-((Stock * nstrich(dOne(Stock, Exercise, Time, Interest, sigma)) * sigma) / (2 * Math.Sqrt(Time))) + Interest * Exercise * Math.Exp(-Interest * Time) * NormSDist(-dOne(Stock, Exercise, Time, Interest, sigma) - sigma * Math.Sqrt(Time)));
        }

        public double CallTheta(double Stock, double Exercise, double Time, double Interest, double sigma)
        {
            return (-((Stock * nstrich(dOne(Stock, Exercise, Time, Interest, sigma)) * sigma) / (2 * Math.Sqrt(Time))) - Interest * Exercise * Math.Exp(-Interest * Time) * NormSDist(dOne(Stock, Exercise, Time, Interest, sigma) - sigma * Math.Sqrt(Time)));
        }

        public double PutRho(double Stock, double Exercise, double Time, double Interest, double sigma)
        {
            return (-Exercise * Time * Math.Exp(-Interest * Time) * NormSDist(-(dOne(Stock, Exercise, Time, Interest, sigma) - sigma * Math.Sqrt(Time))));
        }

        public double CallRho(double Stock, double Exercise, double Time, double Interest, double sigma)
        {
            return (Exercise * Time * Math.Exp(-Interest * Time) * NormSDist(dOne(Stock, Exercise, Time, Interest, sigma) - sigma * Math.Sqrt(Time)));
        }

        public double CallVolatility(double Stock, double Exercise, double Time, double Interest, double Target)
        {
            double High = 2;
            double Low = 0;

            while ((High - Low) > 0.000001)
            {
                if (Call_Option_BSM_Model(Stock, Exercise, Time, Interest, (High + Low) / 2) > Target)
                {
                    High = (High + Low) / 2;
                }
                else
                {
                    Low = (High + Low) / 2;
                }
            }
            return (High + Low) / 2;
        }


        #region Library doubles
        [ComRegisterFunctionAttribute]
        public static void Registerdouble(Type type)
        {
            Registry.ClassesRoot.CreateSubKey(
              GetSubKeyName(type, "Programmable"));
            RegistryKey key = Registry.ClassesRoot.OpenSubKey(
              GetSubKeyName(type, "InprocServer32"), true);
            key.SetValue("",
              System.Environment.SystemDirectory + @"\mscoree.dll",
              RegistryValueKind.String);
        }
        #endregion

        #region Library doubles
        [ComUnregisterFunctionAttribute]
        public static void Unregisterdouble(Type type)
        {
            Registry.ClassesRoot.DeleteSubKey(
              GetSubKeyName(type, "Programmable"), false);
        }

        private static string GetSubKeyName(Type type,
          string subKeyName)
        {
            System.Text.StringBuilder s =
              new System.Text.StringBuilder();
            s.Append(@"CLSID\{");
            s.Append(type.GUID.ToString().ToUpper());
            s.Append(@"}\");
            s.Append(subKeyName);
            return s.ToString();
        }
        #endregion
    }
}
